#pragma warning(disable:4786)       // Turned off warning because of STL map 

#include "slotspin.h"

#include "lib.h"
#include "log.h"

SlotSpin::SlotSpin()
{
    m_stopCount = 0;
    m_multibankBet = 0;
    m_multibankPayout = 0;
    m_spinComplete = false;
    m_spinSaved = false;
    m_spinSent = false;
    m_stops = (uint8 *) 0;
    m_gameNum = 0;
    m_bonusGameType = 0;
    m_bAutoplay = false;
    m_nGameModeId = 0;
    m_nNumSpinsRemaining = 0;
	m_nNumRows = 3;
}

void
SlotSpin::setStops(uint8 stopCount, uint8 *stops)
{
    if ( m_stops != (uint8 *) 0 )
    {
        delete [] m_stops;
    }

    m_stopCount = stopCount;
    m_stops = new uint8[m_stopCount];
    for ( uint8 i = 0; i < m_stopCount; i++ )
    {
        m_stops[i] = stops[i];
    }

}

SlotSpin::~SlotSpin()
{
    delete [] m_stops;

    while ( m_spinLines.size() > 0 )
    {
        SpinLine *spinLine = m_spinLines.back();
        delete spinLine;
        m_spinLines.pop_back();
    }

    while ( m_bonusGames.size() > 0 )
    {
        BonusGame *bonusGame = m_bonusGames.back();
        delete bonusGame;
        m_bonusGames.pop_back();
    }

    clearScatters();
}

bool8 
SlotSpin::getAutoplay()
{
    return m_bAutoplay;
}

void 
SlotSpin::setAutoplay( bool8 bAutoplay)
{
    m_bAutoplay = bAutoplay;
}

int32 
SlotSpin::getNumSpinsRemaining()
{
    return m_nNumSpinsRemaining;
}

void 
SlotSpin::setNumSpinsRemaining( int32 numSpinsRemaining)
{
    m_nNumSpinsRemaining = numSpinsRemaining;
}

uint8 
SlotSpin::getGameModeId()
{
    return m_nGameModeId;
}

void 
SlotSpin::setGameModeId( uint8 nGameModeId)
{
    m_nGameModeId = nGameModeId;
}

uint8
SlotSpin::getSpinLineCount() const
{
    return m_spinLines.size();
}


        
uint8 
SlotSpin::getStopCount() const
{
    return m_stopCount;
}
        
const uint8 *
SlotSpin::getStops() const
{
    return m_stops;
}

        
uint8 
SlotSpin::getBonusGameType() const
{
    return m_bonusGameType;
}
        
void 
SlotSpin::setBonusGameType(uint8 bonusGameType)
{
    m_bonusGameType = bonusGameType;
}

        
BonusGame *
SlotSpin::findBonusGame(uint8 bonusGameNum) const
{
    BonusGame *bonusGame = (BonusGame *) 0;

    for ( uint8 i = 0; m_bonusGames.size() > i; i++ )
    {
        bonusGame = m_bonusGames[i];

        if ( bonusGame->bonusgameindex == bonusGameNum )
        {
            break;
        }
        else
        {
            bonusGame = (BonusGame *) 0;
        }
    }

    return bonusGame;
}

BonusGame*
SlotSpin::addBonusGame(uint8 bonusgametype,uint8 bonusgameindex,int32 basepayoutamount,int32 totalmultiplier,int32 totalbonuspayoutamount,int32 freespins,int64 overridegamenum,bool8 bSaved)
{
    BonusGame *bonusGame = findBonusGame(bonusgameindex);

    if ( bonusGame == (BonusGame *) 0 )
    {
        bonusGame = new BonusGame();

		bonusGame->bonusgametype = bonusgametype;
		bonusGame->bonusgameindex = bonusgameindex;
		bonusGame->basepayoutamount = basepayoutamount;
		bonusGame->totalmultiplier = totalmultiplier;
		bonusGame->totalbonuspayoutamount = totalbonuspayoutamount;
		bonusGame->freespins = freespins;
		bonusGame->bSaved = bSaved;

		if (overridegamenum > 0)
		{
			bonusGame->overrideGameNum(overridegamenum);
		}

        m_bonusGames.push_back(bonusGame);
    }
    else
    {
        /**
         * Duplicate lineid.
         */
		Log::msgWarning("Trying to create a bonus game, but there's already one there: %d", this->m_gameNum);
 //       ASSERT(0);
    }
	return bonusGame;
}


void
SlotSpin::clearBonusGames()
{
	m_bonusGames.clear();
}

uint8
SlotSpin::getNumBonusGames() const
{
    return m_bonusGames.size();
}

BonusGame*
SlotSpin::getBonusGame(uint8 nIndex) const
{
    BonusGame* pBonus = NULL;

    if ( nIndex >= 0 && nIndex < m_bonusGames.size() )
    {
        pBonus = m_bonusGames[nIndex];
    }

    return pBonus;
}
        
int32 
SlotSpin::getTotalBonusPayoutAmount()
{
    int32 payout = 0;

    for ( uint8 i = 0; i < m_bonusGames.size(); i++ )
    {
        BonusGame *bonusGame = m_bonusGames[i];
        payout += bonusGame->totalbonuspayoutamount;
    }

    return payout;
}



SpinLine *
SlotSpin::findSpinLine(uint8 lineid) const
{
    SpinLine *spinLine = (SpinLine *) 0;

    for ( uint8 i = 0; m_spinLines.size() > i; i++ )
    {
        spinLine = m_spinLines[i];

        if ( spinLine->lineid == lineid )
        {
            break;
        }
        else
        {
            spinLine = (SpinLine *) 0;
        }
    }

    return spinLine;
}

        
       
void 
SlotSpin::setJackpotAmount(uint8 lineid, int32 jackpotamount)
{
    SpinLine *spinLine = findSpinLine(lineid);

    if ( spinLine != (SpinLine *) 0 )
    {
        spinLine->basepayoutamount = jackpotamount;
        spinLine->totallinepayoutamount = jackpotamount;
        spinLine->totalmultiplier = 1;
        spinLine->jackpot = true;
    }
    else
    {
        /**
         * No line allocated for this payout.
         */
        ASSERT(0);
    }
}


void
SlotSpin::setPayoutAmount(uint8 lineid, int32 basepayoutamount, int32 totalmultiplier, int32 totallinepayoutamount, bool8 jackpot, uint8 payouttypeid)
{
    SpinLine *spinLine = findSpinLine(lineid);

    if ( spinLine != (SpinLine *) 0 )
    {
        spinLine->basepayoutamount = basepayoutamount;
        spinLine->jackpot = jackpot;
        spinLine->payouttypeid = payouttypeid;
        spinLine->totalmultiplier = totalmultiplier;
        spinLine->totallinepayoutamount = totallinepayoutamount;
    }
    else
    {
        /**
         * No line allocated for this payout.
         */
        ASSERT(0);
    }
}

void
SlotSpin::addLine(uint8 lineid)
{
    SpinLine *spinLine = findSpinLine(lineid);

    if ( spinLine == (SpinLine *) 0 )
    {
        spinLine = new SpinLine();
        spinLine->jackpot = false;
        spinLine->lineid = lineid;
        spinLine->payouttypeid = 0;
        spinLine->basepayoutamount = 0;
        spinLine->totallinepayoutamount = 0;
        spinLine->totalmultiplier = 1;

        m_spinLines.push_back(spinLine);
    }
    else
    {
        /**
         * Duplicate lineid.
         */
        ASSERT(0);
    }

}

void
SlotSpin::setSpinComplete(bool8 flag)
{
    m_spinComplete = flag;
}
        
bool8
SlotSpin::isSpinComplete()
{
    return m_spinComplete;
}


void
SlotSpin::setSpinSent(bool8 flag)
{
    m_spinSent = flag;
}
        
bool8
SlotSpin::isSpinSent()
{
    return m_spinSent;
}


void
SlotSpin::setSpinSaved(bool8 flag)
{
    m_spinSaved = flag;
}
        
bool8
SlotSpin::isSpinSaved()
{
    return m_spinSaved;
}


void
SlotSpin::setMultibankPayout(int32 payout)
{
    m_multibankPayout = payout;
}

void
SlotSpin::setMultibankBet(int32 bet)
{
    m_multibankBet = bet;
}

void
SlotSpin::setBet(uint8 bet)
{
    m_bet = bet;
}
        
SpinLine *
SlotSpin::getSpinLineAt(uint8 index)
{
    SpinLine *spinLine = (SpinLine *) 0;

    if ( index < m_spinLines.size() )
    {
        spinLine = m_spinLines[index];
    }
    else
    {
        /**
          * lineid too large.
          */
		Log::msgWarning("getSpinLineAt: %d", index);
//        ASSERT(0);
    }

    return spinLine;
}

       
SpinLine *
SlotSpin::getSpinLineByLineId(uint8 lineid)
{
    return findSpinLine(lineid);
}

int32
SlotSpin::getMultibankBet() const
{
    return m_multibankBet;
}

int32
SlotSpin::getMultibankPayout() const
{
    return m_multibankPayout;
}



uint8 
SlotSpin::getBet() const
{
    return m_bet;
}
        
bool8 
SlotSpin::getJackpot()
{
    bool8 jackpot = false;


    for (uint8 lineid = 0; !jackpot && lineid < m_spinLines.size(); lineid++ )
    {
        jackpot  = getSpinLineAt(lineid)->jackpot;
    }

    return jackpot;
}


uint16 
SlotSpin::getTotalBet() const
{
    return m_bet * m_spinLines.size();
}
        
int32
SlotSpin::getTotalPayoutAmount()
{
    return getTotalSpinPayoutAmount() + getTotalBonusPayoutAmount();
}


int32
SlotSpin::getTotalSpinPayoutAmount()
{
    int32 payoutamount = 0;
    for ( uint8 i = 0; i < m_spinLines.size(); i++ )
    {
        SpinLine *spinLine = m_spinLines[i];
        payoutamount += spinLine->totallinepayoutamount;
    }

    return payoutamount;
}
        


        
void 
SlotSpin::setGameNum(int64 gameNum)
{
    m_gameNum = gameNum;
}

int64
SlotSpin::getGameNum() const
{
    return m_gameNum;
}

SlotScatter* 
SlotSpin::addScatter( int32 scatterposition, int32 basepayoutamount, int32 totalmultiplier, bool8 jackpot, uint8 payouttypeid, int32 freespins )
{
    SlotScatter* pScatter = new SlotScatter();
    pScatter->scatterid = m_scatters.size();
    pScatter->scatterposition = scatterposition;
    pScatter->basepayoutamount = basepayoutamount;
    pScatter->totalmultiplier = totalmultiplier;
    pScatter->totalscatterpayoutamount = basepayoutamount * totalmultiplier;
    pScatter->jackpot = jackpot;
    pScatter->payouttypeid = payouttypeid;
    pScatter->freespins = freespins;

    m_scatters.push_back(pScatter);

    return pScatter;
}

void 
SlotSpin::clearScatters()
{
    while ( m_scatters.size() > 0 )
    {
        SlotScatter *pScatter = m_scatters.back();
        delete pScatter;
        m_scatters.pop_back();
    }

    m_scatters.clear();
}

uint8 
SlotSpin::getNumScatters() const
{
    return m_scatters.size();
}

SlotScatter* 
SlotSpin::getScatter(uint8 nIndex) const
{
    SlotScatter* pScatter = NULL;

    if ( nIndex >= 0 && nIndex < m_scatters.size() )
    {
        pScatter = m_scatters[nIndex];
    }

    return pScatter;
}

void  
SlotSpin::addWheelViewIcon(uint8 nReel, uint8 nRow, uint8 nIcon)
{
    uint16 key = ( nReel << 8 ) + nRow;
    WheelViewIcons::iterator it = m_mapWheelViewIcons.find(key);

    if ( it == m_mapWheelViewIcons.end() )
    {
        m_mapWheelViewIcons.insert(WheelViewIcons::value_type(key,nIcon));
    }
}

uint8 
SlotSpin::getWheelViewIcon(uint8 nReel, uint8 nRow)
{
    uint16 key = ( nReel << 8 ) + nRow;
    uint8 result = 255;

    WheelViewIcons::iterator it = m_mapWheelViewIcons.find(key);

    if ( it != m_mapWheelViewIcons.end() )
    {
        result = it->second;
    }

    return result;
}

void SlotSpin::setNumRows(uint8 nRows)		// Needed for games with more than 3 rows (i.e. Football Frenzy)
{
	m_nNumRows = nRows;
}

uint8 SlotSpin::getNumRows()					// Needed for games with more than 3 rows (i.e. Football Frenzy)
{
	return m_nNumRows;
}

